package com.liusy.event;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

import javax.management.RuntimeErrorException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;

import test.event.TestObservableEvent;
import test.event.TestObserver;


/**
 * 系统级事件广播接口  单例 注：事件类型必须保持统一性
 * 
 * @author liusy 2012-04-03
 */
public class ApplicationBroadcastEvent extends Observable {
	
	private static Logger log = Logger.getLogger(ApplicationBroadcastEvent.class);
	
	private static ApplicationBroadcastEvent instance = new ApplicationBroadcastEvent();
	
	private Map<Object,String> types = new Hashtable<Object,String>();

	
	private Field f_obs;
	private Field f_changed;
	
	public static void init(){
		
	}
	
	public static ApplicationBroadcastEvent getInstance(){
		return instance;
	}

	/**
	 * 
	 *　@throws RuntimeException
	 */
	private ApplicationBroadcastEvent() {
		log.debug("construct");
		try {
			f_obs = Observable.class.getDeclaredField("obs");
			f_obs.setAccessible(true);//把方法的访问属性设置为true
			
			f_changed = Observable.class.getDeclaredField("changed");
			f_changed.setAccessible(true);//把方法的访问属性设置为true
		} catch (Exception e) {
			log.error("初始化对象失败，无法读取父类私有属性",e);
			throw new RuntimeException(e);
		} 
	}
	
	/**
	 * 观察者列表
	 * @return
	 */
	public Vector<Observer> getObservers(){
		Vector<Observer> obs = null;
		try {
            obs = (Vector<Observer>) f_obs.get(this);
		} catch (Exception e) {
			log.error("读取父类私有属性 obs 值失败",e);
			throw new RuntimeException(e);
		}
		return obs;
	}
	
	/**
	 * 方法已禁用，请调用 {@link #addObserver(String, Observer)}；
	 */
	@Override
	@Deprecated
	public synchronized void addObserver(Observer o) {
		//super.addObserver(o);
		throw new RuntimeException("方法已禁用，请调用：addObserver(String type, Observer o) ");
	}
	
	/**
	 * 注册观察者
	 * @param type 观察者关注的事件类型
	 * @param o 观察者对象
	 * @throws NullPointerException
	 */
	public synchronized void addObserver(String type, Observer o) {
		if (type == null)
            throw new NullPointerException();
		super.addObserver(o);
		types.put(o, type);
	}
	
	@Override
	public synchronized void setChanged() {
		super.setChanged();
	}
	
	/**
	 * 更新前置动作
	 * @param arg
	 * @throws RuntimeException
	 */
	public List<?> before(Object arg){
		assertArg(arg);
        Object[] arrLocal;
        
        synchronized (this) {
        	try {
				if (!f_changed.getBoolean(this))
				        return Collections.emptyList();
			} catch (Exception e) {
				log.error("读取状态出错。",e);
				throw new RuntimeException(e);
			}finally{
			}
        	
			arrLocal = getObservers().toArray();
			clearChanged();
        }
        
        List<Object> result = new ArrayList<Object>();
		Object rs;
		
        for (int i = arrLocal.length-1; i>=0; i--){
        	String obsType = types.get(arrLocal[i]);
        	if( obsType.equals( ((IEvent)arg).getType()) ){//处理对应事件
        		rs = ((IEventObserver)arrLocal[i]).before(this, arg);
	        	if(rs!=null){
	        		result.add(rs);
	        	}
        	}else{
        		log.debug(arg+"不是观察者["+ arrLocal[i] + "]期望的事件类型[" + obsType + "]，不进行处理。");
        	}
        }
        return result;
	}
	
	/**
	 * @throws RuntimeErrorException
	 */
	@Override
	public void notifyObservers(Object arg) {
		assertArg(arg);
		setChanged();
        Object[] arrLocal;
        
		synchronized (this) {
		    try {
				if (!f_changed.getBoolean(this))
				        return;
			} catch (Exception e) {
				log.error("读取状态出错。",e);
				throw new RuntimeException(e);
			}finally{
			}
            arrLocal = getObservers().toArray();
            clearChanged();
		}

	    for (int i = arrLocal.length-1; i>=0; i--){
	    	String obsType = types.get(arrLocal[i]);
        	if( obsType.equals( ((IEvent)arg).getType()) ){//处理对应事件
        		((Observer)arrLocal[i]).update(this, arg);
        	}else{
        		log.debug(arg+"不是观察者["+ arrLocal[i] + "]期望的事件类型[" + obsType + "]，不进行处理。");
        	}
	    }
	}
	
	/**
	 * 完成更新后处理器
	 * @param arg
	 * @return
	 */
	public List<?> after(Object arg){
		assertArg(arg);
		Object[] arrLocal;
        
		synchronized (this) {
        	try {
				if (!f_changed.getBoolean(this))
				        return Collections.emptyList();
			} catch (Exception e) {
				log.error("读取状态出错。",e);
				throw new RuntimeException(e);
			}finally{
			}
        	
			arrLocal = getObservers().toArray();
			clearChanged();
        }
		
		List<Object> result = new ArrayList<Object>();
		Object rs;
		for (int i = arrLocal.length-1; i>=0; i--){
        	String obsType = types.get(arrLocal[i]);
        	if( obsType.equals( ((IEvent)arg).getType()) ){//处理对应事件
        		rs = ((IEventObserver)arrLocal[i]).after(this, arg);
	        	if(rs!=null){
	        		result.add(rs);
	        	}
        	}else{
        		log.debug(arg+"不是观察者["+ arrLocal[i] + "]期望的事件类型[" + obsType + "]，不进行处理。");
        	}
        }
        return result;
	}
	
	/**
	 * @param arg
	 * @throws RuntimeException
	 */
	private void assertArg(Object arg){
		if(arg instanceof IEvent){
		}else{
			throw new IllegalArgumentException("[" +arg+ "]不是期望的参数类型:"+IEvent.class);
		}
	}
	
		
}
